package net.miranti.download;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.tidy.Tidy;

public class DownloadManager {
	enum Month {
		JAN, FEV, MAR, ABR, MAI, JUN, JUL, AGO, SET, OUT, NOV, DEZ
	}

	private static int BUFFER_SIZE = 4096;
	private String sourceUrl;
	private String destinationFolder;

	public DownloadManager(String sourceUrl, String destinationFolder) {
		this.sourceUrl = sourceUrl;
		this.destinationFolder = destinationFolder;
	}

	public TreeMap<String, File> downloadFiles() {
		Map<String, String> date2File = getDate2FileMap();
		TreeMap<String, File> filesByPeriod = new TreeMap();

		for (Entry<String, String> entry : date2File.entrySet()) {
			try {
				String filename = entry.getValue();
				String localFilename = destinationFolder + File.separator 
					+ filename.substring(filename.lastIndexOf("/") + 1).replaceAll("%20", " ");
				
				filesByPeriod.put(entry.getKey(), 
						downloadFile(sourceUrl + filename, localFilename));
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return filesByPeriod;
	}

	private Map<String, String> getDate2FileMap() {
		Map<String, String> date2File = new HashMap();

		byte[] bytes = parseHtmlToFindFilesTable().getBytes();
		Document d = new Tidy().parseDOM(new ByteArrayInputStream(bytes),
				System.out);
		NodeList rows = d.getElementsByTagName("table").item(0).getChildNodes();
		int n = rows.getLength();
		for (int i = 1; i < n; i++) {
			NodeList columns = rows.item(i).getChildNodes();

			String year = columns.item(0).getChildNodes().item(0)
					.getNodeValue();

			Node monthsTable = columns.item(1).getChildNodes().item(0);
			NodeList monthsColumns = monthsTable.getChildNodes().item(0)
					.getChildNodes();

			int nMonths = monthsColumns.getLength();
			for (int j = 0; j < nMonths; j++) {
				Node monthLink = monthsColumns.item(j).getChildNodes().item(0);
				Node hrefNode = monthLink.getAttributes().getNamedItem("href");
				if (hrefNode == null)
					break;
				String href = parseHref(hrefNode.getNodeValue());
				String month = monthLink.getChildNodes().item(0).getNodeValue();

				int m = Month.valueOf(month).ordinal() + 1;
				String monthAsNumber = m < 10 ? "0" + m : String.valueOf(m);

				date2File.put(year + "-" + monthAsNumber, href);
			}
		}
		return date2File;
	}

	private String parseHref(String href) {
		int startIndex = href.indexOf("\'");
		int endIndex = href.lastIndexOf("\'");

		return href.substring(startIndex + 1, endIndex);
	}

	private String parseHtmlToFindFilesTable() {
		BufferedReader in = null;
		try {
			URL url = new URL(sourceUrl + "/movi.php?gi=movi");
			InputStream is = url.openStream();
			in = new BufferedReader(new InputStreamReader(is));

			String str;
			while ((str = in.readLine()) != null)
				if (str.indexOf("As tabelas mostram o movimento de aeronaves") != -1)
					break;

			int startIndex = 0, endIndex;
			while ((str = in.readLine()) != null) {
				startIndex = str.indexOf("<table");
				if (startIndex != -1)
					break;
			}

			StringBuilder sb = new StringBuilder(str.substring(startIndex));
			while ((str = in.readLine()) != null) {
				endIndex = str.indexOf("javascript:history.go(-1);");
				if (endIndex != -1)
					break;
				sb.append(str);
			}
			endIndex = sb.lastIndexOf("</table>") + "</table>".length();
			return sb.substring(0, endIndex);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (in != null)
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		return null;
	}

	private File downloadFile(String url, String destination)
			throws IOException {
		copyStream(new URL(url).openStream(), new FileOutputStream(destination));
		return new File(destination);
	}

	private void copyStream(InputStream in, OutputStream out)
			throws IOException {
		try {
			byte[] buf = new byte[BUFFER_SIZE];
			int len;
			while ((len = in.read(buf)) > 0)
				out.write(buf, 0, len);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			in.close();
			out.close();
		}
	}
}
